This document describes the difference of cryptocurrencies between several plateforms. The goal is to study wether or not some arbitrage opportunities exist, and if so where are the best options.

library(tidyverse)
library(rmarkdown)    # You need this library to run this template.
library(epuRate)      # Install with devtools: install_github("holtzy/epuRate", force=TRUE)
library(DT)
library(plotly)
library(hrbrthemes)

1 - Dataset


This document is based on a dataset described here and available here. Basically it report the price of 5 currencies (BTC, ETH, BCH, XRP, LTC) on 4 exchanges (Kraken, Bitstamp, Cex, Bitfinex). All currencies are not necessarily available on each plateform, as described in the table below:

# Load result
load("DATA/public_ticker_harvest.Rdata")
Ticker$last <- as.numeric(Ticker$last)
Ticker %>% nrow()
## [1] 799487
Ticker= head(Ticker, 100000)

2 - Show the trend


Cryptocurrency prices evolves quickly. At each timestamp, we can have a look to the prices of Bitcoin on every platform. If you are interested by this curve, note that they are provided for every currency here.

p <- Ticker %>%
  filter(symbol=="BTCEUR") %>%
  ggplot( aes(x=time, y=last, color=platform, group=platform)) +
    geom_line() +
    theme_ipsum()
ggplotly(p)

If we zoom on a specific area, it is obvious that the price is not exactly the same on every platform.

p <- Ticker %>%
  head(10000) %>%
  filter(symbol=="BCHEUR") %>%
  ggplot( aes(x=time, y=last, color=platform, group=platform)) +
    geom_line() +
    theme_ipsum()
ggplotly(p)

3 - Differences


Can we try to quantify the difference? At each timestamp, we can calculate the difference between 2 exchanges, in euros and in %. We can then represent this difference. Here is an example with the difference between Bitstamp and Cex.

plot_last_difference <- function(plat1, plat2){

  # First I calculate the differnce of the 'last' price between both exchanges:
  diff <- Ticker %>%
    filter(platform %in% c(plat1, plat2)) %>%
    select(time, platform, last, symbol) %>%
    spread(platform, last) %>%
    mutate(diff=.[[4]] - .[[3]], diff_perc=(.[[4]] - .[[3]]) / .[[4]] *100 ) %>%
    filter(!is.na(diff_perc))
  
  # Then I plot the result
  ggplot(diff, aes(x=time, y=diff_perc, group=symbol, fill=symbol)) +
      geom_area() +
      facet_wrap(~symbol, nrow=5) +
      theme(legend.position="none") 
}

3.1 Cex-Bitstamp

plot_last_difference("Cex", "Bitstamp")

3.2 Kraken-Bitstamp

plot_last_difference("Kraken", "Bitstamp")

3.3 Kraken-Bitfinex

plot_last_difference("Kraken", "Bitfinex")

4 - What we really get


It’s important to note that we buy crypto at the ask price, and sell it at the bid price. For each time stamp, I can calculate the potential gain taking that into account:

# A function that calculates the difference between 2 platforms for every currency at each time stamp
find_askbid_difference <- function(plat1, plat2){
  
  diff <- Ticker %>% 
    filter(platform %in% c(plat1, plat2)) %>%
    select(time, platform, symbol, ask, bid) %>%
    mutate(ask=as.numeric(ask), bid=as.numeric(bid)) %>%
    gather(temp, value, -time, -platform, -symbol) %>%
    mutate(platform=gsub(plat1,"plat1", platform)) %>%
    mutate(platform=gsub(plat2,"plat2", platform)) %>%
    unite(temp1, platform, temp, sep="_") %>%
    spread( key=temp1, value=value) %>%
    mutate( 
      diff1=(plat1_bid-plat2_ask)/plat1_bid*100, 
      diff2=(plat2_bid-plat1_ask)/plat2_bid*100
    ) %>%
    rowwise() %>%
    mutate( diff_perc=max(diff1, diff2) ) %>%
    filter(!is.na(diff_perc))
  return(diff)
}

plot_askbid_difference <- function(diff){
  p <- ggplot(diff, aes(x=time, y=diff_perc, group=symbol, fill=symbol)) +
        geom_area() +
        facet_wrap(~symbol, nrow=5) +
        theme(legend.position="none") 
    
  ggplotly(p)
} 

4.1 Cex-Bitstamp

# Find differences between kraken and bitstamp
diff <- find_askbid_difference("Cex", "Bitstamp")
plot_askbid_difference(diff)

4.2 Kraken-Bitstamp

# Find differences between kraken and bitstamp
diff <- find_askbid_difference("Kraken", "Bitstamp")
plot_askbid_difference(diff)

5 - Significant difference

What interest us is the number of time the difference between 2 platforms reaches a threshold that allow to perform arbitrage. Let’s try to quantify how many times we reach this threshold for every currency between kraken and bitstamp.

# A function that counts the number of significant differences for several threshold
find_signif_diff <- function(diff){
  nbSignifDiff=data.frame()
  for( i in seq(0.7,4,0.2)){
    df <-  diff %>%
      group_by(symbol) %>%
      filter(diff_perc > i) %>%
      summarise( nb_over_thres = n() ) %>%
      mutate( thres = i) %>%
      arrange( nb_over_thres )
    nbSignifDiff <- rbind( nbSignifDiff, df)
  }
  return(nbSignifDiff)
}

# A function that plot this number of diff
plot_signif_diff <- function(nbSignifDiff){
  ggplot(nbSignifDiff, aes(x=thres, y=nb_over_thres, group=symbol, color=symbol)) +
    geom_line() +
    ylab("Number of cases in x days") +
    xlab("Difference threshold (%)")
}

# Apply that to a first example:
diff <- find_askbid_difference("Cex", "Bitstamp")
nbSignifDiff <- find_signif_diff(diff)
plot_signif_diff(nbSignifDiff)

Now, let’s make this calculation for every pair of plateform.

# find all the pairs of platform
list_platforms <- Ticker$platform %>% unique() %>% as.character()
list_pairs <- combn(list_platforms, 2)

# find the number of significant differences for each pair
bilan=data.frame()
for(i in c(1:ncol(list_pairs))){
  diff <- find_askbid_difference(list_pairs[1,i], list_pairs[2,i])
  nbSignifDiff <- find_signif_diff(diff)
  nbSignifDiff$pair <- paste( list_pairs[1,i], list_pairs[2,i], sep="-")
  bilan <- rbind(bilan, nbSignifDiff)
}

#
ggplot(bilan, aes(x=thres, y=nb_over_thres, group=symbol, color=symbol)) +
  geom_line() +
  ylab("Number of cases in x days") +
  xlab("Difference threshold (%)") +
  facet_wrap(~pair, ncol=5)

6 - Conclusion


 

A work by Yan Holtz

Yan.holtz.data@gmail.com